/*
 This file is part of WebHUD.

 WebHUD is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 any later version.

 WebHUD is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with WebHUD.  If not, see <http://www.gnu.org/licenses/>.
 */

#import "WHController.h"
#import "Constants.h"
#import "Safari.h"
#import "WHApi.h"
#import "WHHelper.h"
#import "LocationChangeHandler+WHWebFrameLoadDelegate.h"

// Fake src definition, because we know DOMHTMLImageElement and DOMHTMLEmbedElement implement it
@interface DOMElement (WHDOMElement)
- (NSString *)href;
- (NSString *)rel;
- (NSString *)title;
@end

@implementation WHController

/**********************************************************************
 * initializer
 */
- (id)init
{
    self = [super init];
    if (self != nil) {

        if (!([[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Safari"] ||
              [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"org.webkit.nightly.WebKit"]
              ))
            return nil;

        // The magic happens here!
        [LocationChangeHandler swizzle];

        // load Nib File
        if (![NSBundle loadNibNamed:@"WebHUD" owner:self])
        {
            NSLog(@"Warning! Could not load 'WebHUB' nib file.\n");
            return nil;
        }

        // Initialize the WebView
        [webview setFrameLoadDelegate: self];
        [webview setPolicyDelegate: self];
        [webview setDrawsBackground: NO];

        [panel setDelegate: self];

        // create the WH Api
        api = [WHApi make];

        NSLog(@"WHController::init() panel= %@", self.panel);
    }
    return self;
}

/**********************************************************************
 * Update HUD
 */


- (void)getHUDLinks:(NSMutableDictionary *)newLinks
              order:(NSMutableArray *)newOrder
          fromFrame:(WebFrame *)frame
{
    NSLog(@"getHUDLinks:order:fromFrame");

    // XPATH query in mainFrame DOM for <link rel="hud" ...>
    DOMXPathResult* elements = [[frame DOMDocument] evaluate:@"//link[@rel='hud']"
                                                 contextNode:[[frame DOMDocument] documentElement]
                                                    resolver:nil
                                                        type:DOM_ANY_TYPE
                                                    inResult:nil];

    DOMElement *element;
    while (element = (DOMElement *)[elements iterateNext]) {
        if ([element respondsToSelector:@selector(href)] &&
            [element respondsToSelector:@selector(title)] &&
            [element respondsToSelector:@selector(rel)] ) {
            NSLog(@"WebHub: found <link href=%@ rel=%@ title=%@>",
                    [element href], [element rel], [element title]);

            [newLinks setObject:[element href] forKey: [element title]];
            [newOrder addObject: [element title]];
        }
    }
}

- (void)updateWithFrame:(WebFrame *)frame
{
    NSLog(@"updateWithFrame: %@", frame);

    NSMutableDictionary *newURLs = [[NSMutableDictionary alloc] init];
    NSMutableArray      *newOrder = [[NSMutableArray alloc] init];
    
    // Set the master WebView such that we can refer to it
    // later
    api.masterWebFrame = frame;
    
    // fetch new links
    [self getHUDLinks: newURLs
                order: newOrder
            fromFrame: frame];

    // get the URL of the main Frame
    NSString *url = [[[[frame dataSource] request] URL] absoluteString];
    NSLog(@"frame URL: %@ old URL: %@", url, mainFrameURL);

    // Update TabView
    [self updateTabsWithLinks: newURLs
                        order: newOrder
                        merge: [mainFrameURL isEqual: url]];

    // update the URL we're bound to
    mainFrameURL = [url retain];

    // set panel visible if we have URLs
    if ([urls count]) {
        [panel setIsVisible: YES];
    } else {
        [panel setIsVisible: NO];
    }
}

-(void)updateTabsWithLinks:(NSMutableDictionary *)newLinks
                     order:(NSMutableArray *)newOrder
                     merge:(bool)doMerge
{
    int selected = 0;
    bool do_load_url = true;
    NSString *selected_title = nil;

    NSLog(@"updateTabsWithLinks:order:merge");

    //NSLog(@"newLinks %@, urls %@", newLinks, urls);

    if (1 && doMerge) {
        int new_selection = 0;
        // the main frame url did not change.
        // We must not reload the currently selected
        // tab if it's still valid.
        selected = [segControl selectedSegment];
        NSLog(@"selected=%d", selected);
        selected_title = [order objectAtIndex: selected];
        NSLog(@"selected_title=%@", selected_title);

        // check if the selection is still valid after
        // the update, and select that one if so
        new_selection = [newOrder indexOfObjectIdenticalTo: selected_title];
        if (new_selection != NSNotFound) {
            NSLog(@"new_selected=%d", new_selection);
            selected = new_selection;
            do_load_url = false; // dont need to reload. tab still valid.
        }

    }

    // update order and links
    order = newOrder;
    urls = newLinks;

    // create new tab layout based on order and titles
    [segControl setSegmentCount: [order count]];
    int index= 0;
    for (NSString *title in newOrder) {
        [segControl setLabel: title forSegment: index++];
    }
    [self resizeSegmentedControl];

    [[segControl cell] setSelectedSegment: selected];
    if (do_load_url) {
        [self loadUrl: [newLinks objectForKey:[order objectAtIndex: selected]]];
    }
}

- (void)resizeSegmentedControl
{
    NSRect r = [webview bounds];
    int n = [order count];
    if (n>0) {
        int index = 0;
        CGFloat width = r.size.width / n;
        for (index=0; index<n; index++) {
            [segControl setWidth: width forSegment: index];
        }
    }
}

- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize
{
    [self resizeSegmentedControl];
    return proposedFrameSize;
}

- (void)loadUrl:(NSString *)url
{
    NSLog(@"URL to load: %@", url);
    if (url)
        [[webview mainFrame] loadRequest:[NSURLRequest
                          requestWithURL:[NSURL URLWithString: url]]];
}

- (IBAction)segControlClicked:(id)sender
{
    NSLog(@"segControlClicked: %@", sender);
    int clickedSegment = [sender selectedSegment];
    NSString *label = [[sender cell] labelForSegment:clickedSegment];
    NSLog(@"label: %@", label);
    
    NSString *url = [urls objectForKey: label];
    NSString *current_url = [[[[[webview mainFrame] dataSource] request] URL] absoluteString];

    NSLog(@"[current_url isEqual: url] = %s", [current_url isEqual: url]?"YES":"NO");
    
    if ([current_url isEqual: url] == NO && (!is_redirect)) {
        [self loadUrl: url];
    }
    
}

/**********************************************************************
 * WebKit WebPolicyDelegate Methods
 */
- (void)webView:(WebView *)sender
decidePolicyForNewWindowAction:(NSDictionary *)actionInformation
                       request:(NSURLRequest *)request
                  newFrameName:(NSString *)frameName
              decisionListener:(id < WebPolicyDecisionListener >)listener
{
    NSLog(@"webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:");

    [listener use];
}

- (void)webView:(WebView *)sender
decidePolicyForNavigationAction:(NSDictionary *)actionInformation
                        request:(NSURLRequest *)request
                          frame:(WebFrame *)frame
               decisionListener:(id < WebPolicyDecisionListener >)listener
{
    NSLog(@"webView:decidePolicyForNavigationAction:request:newFrameName:decisionListener:");

    if (is_redirect) {
        NSLog(@"*** REDIRECT DETECTED ignoring action ***");
        is_redirect = false;
        [listener ignore];
    } else {
        [listener use];
    }
}

/**********************************************************************
 * WebKit frameLoadDelegate Methods
 */
- (void)webView:(WebView *)sender
didClearWindowObject:(WebScriptObject *)windowObject
            forFrame:(WebFrame *)frame
{
    NSLog(@"webView:didClearWindowObject:forFrame:");

    // set it to the HUD panel wso
    [windowObject setValue:api forKey:@"HUD"];
    [sender setHidden: YES];

    // clear the "is_redirect" flag. This delegate method is one
    // of the first things called, so we ought to be save
    is_redirect = false;
}

- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
{
    NSLog(@"webView:didFInishLoadForFrame:");
    
    NSString * script= @"document.getElementsByTagName('body')[0].style['background-color'] = 'transparent';";
    [[sender windowScriptObject] evaluateWebScript:script];
    [sender setHidden: NO];

}

- (void)webView:(WebView *)sender
didReceiveServerRedirectForProvisionalLoadForFrame:(WebFrame *)frame
{
    NSLog(@"webView:didReceiveServerRedirectForProvisionalLoadForFrame:");

    is_redirect = true;
	[api loadUrlInMainFrame: [[[[frame dataSource] request] URL] absoluteString]];
}

- (void)webView:(WebView *)sender
willPerformClientRedirectToURL:(NSURL *)URL
                         delay:(NSTimeInterval)seconds
                      fireDate:(NSDate *)date
                      forFrame:(WebFrame *)frame
{
    NSLog(@"webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:");

    is_redirect = true;
	[api loadUrlInMainFrame: [URL absoluteString]];
}

/**********************************************************************
 * Properties
 */
@synthesize panel;
@synthesize webview;
@synthesize segControl;
@synthesize urls;
@synthesize order;
@synthesize mainFrameURL;
@synthesize redirectUrl;

/**********************************************************************
 * WHController is a Singleton.
 */
+ (void)initialize
{
    // Force the creation of the singleton
    [WHController sharedController];
}

static WHController *sharedController = nil;

+ (WHController*)sharedController
{
    @synchronized(self) {
        if (sharedController == nil) {
            [[self alloc] init];
        }
    }
    return sharedController;
}

+ (id)allocWithZone:(NSZone *)zone
{
    @synchronized(self) {
        if (sharedController == nil) {
            sharedController = [super allocWithZone:zone];
            return sharedController;
        }
    }
    return nil;
}

- (id)copyWithZone:(NSZone *)zone
{
    return self;
}

- (id)retain
{
    return self;
}

- (unsigned)retainCount
{
    return UINT_MAX;
}

- (void)release
{
    // do nothing
}

- (id)autorelease
{
    return self;
}

@end

/* vim: set ts=4 sw=4 expandtab: */
